package com.shareware.common.utils

import android.annotation.TargetApi
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.shareware.common.NUMBER_TEN

/**
 * desc: 功能描述
 * email: mobiledeveloper@qq.com
 */

interface IPermissionListener {
    fun onPermission(success: Array<String>, denied: Array<String>, never: Array<String>)
}

class Permission constructor(activity: FragmentActivity) {

    private var mPermissionFragment: PermissionFragment? = null

    init {
        mPermissionFragment = getPermissionsFragment(activity)
    }

    private fun getPermissionsFragment(activity: FragmentActivity): PermissionFragment {
        val fragment = activity.supportFragmentManager.findFragmentByTag(TAG)
        val permissionFragment: PermissionFragment
        return if (fragment == null) {
            permissionFragment = PermissionFragment()
            val fragmentManager = activity.supportFragmentManager
            fragmentManager.beginTransaction().add(permissionFragment, TAG)
                .commitAllowingStateLoss()
            fragmentManager.executePendingTransactions()
            permissionFragment
        } else {
            fragment as PermissionFragment
        }
    }


    /**
     * 检查权限 permission []
     */
    @TargetApi(Build.VERSION_CODES.M)
    fun checkPermissions(permissions: Array<String>): List<String> {
        return mPermissionFragment!!.checkPermissions(permissions)
    }

    /**
     * 申请权限 permission []
     */
    @TargetApi(Build.VERSION_CODES.M)
    fun requestPermissions(permissions: Array<String>, callback: IPermissionListener) {
        mPermissionFragment!!.requestPermissions(permissions, callback)
    }

    companion object {
        private const val TAG = "PERMISSION_FRAGMENT"
    }
}

internal class PermissionFragment : Fragment() {

    private var listeners = HashMap<String, IPermissionListener>()
    private val permissionRequestCode = NUMBER_TEN

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        retainInstance = true
    }

    @TargetApi(Build.VERSION_CODES.M)
    fun checkPermissions(permissions: Array<String>): List<String> {
        if (activity == null) {
            return listOf()
        }
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return permissions.toList()
        }
        val result = permissions.partition { permission ->
            activity!!.checkSelfPermission(
                permission
            ) == PackageManager.PERMISSION_GRANTED
        }
        return result.first
    }

    @TargetApi(Build.VERSION_CODES.M)
    fun requestPermissions(permissions: Array<String>, callback: IPermissionListener) {
        val key = generateKey(permissions)
        if (listeners.containsKey(key)) {
            return
        }
        listeners[key] = callback
        requestPermissions(permissions, permissionRequestCode)
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == permissionRequestCode) {
            val partition = grantResults.zip(permissions)
                .partition { it.first == PackageManager.PERMISSION_GRANTED }
            val others = partition.second.asSequence().map {
                it.second
            }.partition {
                shouldShowRequestPermissionRationale(it)
            }
            val key = generateKey(permissions)
            listeners[key]?.onPermission(
                partition.first.map { it.second }.toTypedArray(), others.first.toTypedArray(),
                others.second.toTypedArray()
            )
            listeners.remove(key)
        }
    }

    private fun generateKey(permissions: Array<out String>): String {
        return with(StringBuilder()) {
            permissions.forEach {
                append(it)
            }
        }.toString().encodeMd5()
    }
}